import json
import random

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

from cola.god import God
from cola.models import *
from cola.util.id_worker import worker
from cola.util.logger import logger

connected = {}


class OrderConsumer(WebsocketConsumer):

    # 建立连接
    def connect(self):
        self.space_name = self.scope['url_route']['kwargs']['space_name']
        self.username = self.scope['url_route']['kwargs']['username']
        self.space_group_name = 'sang_%s' % self.space_name

        # Join space group
        async_to_sync(self.channel_layer.group_add)(
            self.space_group_name,
            self.channel_name
        )

        # 接受连接，不接收不连接
        self.accept()
        # 将用户和房间信息保留
        cn = connected.get(self.space_name)
        # 帧空间
        frame_space = {}
        users = None
        angel = None
        if cn:
            users = cn.get('users')
            frame_space = cn.get('frame_space')
            angel = cn.get('angel')
        if not users:
            users = {self.username: self}
        elif self.username not in users:
            users[self.username] = self
        connected[self.space_name] = {'users': users, 'frame_space': frame_space, 'angel': angel}
        # 发送连接信息给客户端
        self.issue_role()

    # 断开连接
    def disconnect(self, close_code):
        # Leave space group
        async_to_sync(self.channel_layer.group_discard)(
            self.space_group_name,
            self.channel_name
        )

        group = connected.get(self.space_name)
        if group and group.get('users') and (self.username in group['users']):
            # 断开连接后从组中删除此用户
            del group['users'][self.username]
        group = connected.get(self.space_name)
        if not group or not group.get('users'):
            # 如果区间中已经没有连接，区间状态从游戏中更改为关闭
            if group and group['angel']:
                angel = group['angel']
                angel.stop()
            try:
                space = Space.objects.get(space_name=self.space_name, status=2)
                space.status = 0
                space.save()
            except Space.DoesNotExist:
                pass

    # Receive order from WebSocket 从客户端发送的包中获取消息
    def receive(self, text_data):
        try:
            text_data_json = json.loads(text_data)

            # 从包中获取消息，前端的字段为order
            order = text_data_json.get('order')
            info = text_data_json.get('info')

            if order and order['type'] == 'image':
                logger.info('frame_receive...')
                group = connected.get(self.space_name)
                point = order.get('cmd')
                dead_users = group.get('dead_users')
                if point.get('state') == 1:
                    angel = group.get('angel')
                    for p in point.get('points'):
                        angel.generate(p.get('x'), p.get('y'))
                elif not dead_users or self.username not in dead_users:
                    frame_space = group['frame_space']
                    frame_space[self.username] = order.get('cmd')
                return

            if order and order['type'] == 'see':
                logger.info('see_receive...')
                group = connected.get(self.space_name)
                cmd = order.get('cmd')
                sign = cmd.get('sign')
                angel = group.get('angel')
                tetris_neutral = angel.dusts_neutral.get(sign)
                tetris_pervert = angel.dusts_pervert.get(sign)
                tetris_convert = angel.dusts_convert.get(sign)
                see = group.get('see')
                if not see:
                    group['see'] = {}
                    see = group['see']
                has_sign = False
                if tetris_neutral:
                    del angel.dusts_neutral[sign]
                    see[sign] = self.username
                    has_sign = True
                if tetris_pervert:
                    del angel.dusts_pervert[sign]
                    see[sign] = self.username
                    has_sign = True
                if tetris_convert:
                    # 此种情况认为服务端更新不及时，故而导致服务端误判导致尘埃变异，依然清除此尘埃
                    del angel.tetris_convert[sign]
                    see[sign] = self.username
                    has_sign = True
                if not has_sign:
                    # 当没有找到sign的时候，认为尘埃被其他蛇吃了，已经成为其他蛇的一部分，故此蛇装上去会死
                    order['type'] = 'dead'
                    cmd['by'] = see.get(sign)
                    del cmd['sign']

            if order and order['type'] == 'dead':
                group = connected.get(self.space_name)
                dead_users = group.get('dead_users')
                if not dead_users:
                    group['dead_users'] = []
                    dead_users = group['dead_users']
                dead_users.append(self.username)
                frame_space = group['frame_space']
                thing = frame_space.get(self.username)
                if thing:
                    thing['points'] = []



            # Send order to space group 将要广播的消息添加至包中，字段为order和username
            async_to_sync(self.channel_layer.group_send)(
                self.space_group_name,
                {
                    'type': 'sang_msg',
                    'username': self.username,
                    'order': order,
                    'info': info,
                }
            )
        except Exception as e:
            logger.error('解析客户端消息出现了问题', text_data, e)

    # Receive order from space group
    def sang_msg(self, event):
        username = event['username']
        order = event.get('order')
        info = event.get('info')

        # Send order to WebSocket 发送到ws连接中
        self.send(text_data=json.dumps({
            'username': username,
            'order': order,
            'info': info,
        }))

    # 发送信息
    def send_info(self, info, user=None):
        user = user if user else self.username
        async_to_sync(self.channel_layer.group_send)(
            self.space_group_name,
            {
                'type': 'sang_msg',
                'username': user,
                'info': info,
            }
        )

    # 发送指令
    def send_order(self, **kwargs):
        order = kwargs.get('order')
        mold = kwargs.get('mold')
        cmd = kwargs.get('cmd')
        user = kwargs.get('user')
        user = user if user else self.username
        order = order if order else {
            'type': mold,
            'cmd': cmd,
        }
        async_to_sync(self.channel_layer.group_send)(
            self.space_group_name,
            {
                'type': 'sang_msg',
                'username': user,
                'order': order,
            }
        )

    # 页面执行的脚本
    def cmd(self, cmd="console.log('神谕')"):
        self.send_order(mold='start', cmd=cmd, user='god')

    # 下发角色
    def issue_role(self):
        group = connected.get(self.space_name)
        roles = list(group.get('users').keys())
        serial = len(roles) - 1
        info = {
            "serial": serial,
            "roles": roles,
        }
        self.send_info(info)

    # 生成尘埃
    def drop(self):
        self.send_order(mold='drop', cmd=random.randint(0, 20), user='god')

    # 渲染画面
    def render(self):
        group = connected.get(self.space_name)
        frame_space = group['frame_space']
        self.send_order(mold='render', cmd=list(map(lambda x: dict(x), list(frame_space.values()))), user='god')
        # frame_space.clear()

    # 开始游戏
    def start(self):
        self.send_order(mold='start', cmd=worker.get_id(), user='god')
        group = connected.get(self.space_name)
        if not group:
            logger.error("group已不存在，无法开始游戏。。。")
            return
        angel = group.get('angel')
        if not angel:
            angel = God(56, 30, group)
            angel.start()
            group['angel'] = angel

    # 开始游戏
    def stop(self):
        self.send_order(mold='end', user='god')
